<template>
  <div class="map-box">
    <div id="MAP"></div>
    <div class="search-box" v-show="mapCfg.show_search">
      <el-input
        id="MAP-SEARCH"
        v-model="searchWord"
        placeholder="请输入地址搜索"
        @change="mapSearch"
      ></el-input>
    </div>
    <div class="type-box" v-show="mapCfg.show_type">
      <el-button-group>
        <el-button
          :type="btn.value == mapType.active ? 'primary' : 'default'"
          v-for="btn in mapType.list"
          @click="mapTypeClick(btn)"
          >{{ btn.text }}</el-button
        >
      </el-button-group>
    </div>
    <div class="draw-box" v-show="drawEditor">
      <el-button type="danger" @click="mapDrawClose">完成编辑</el-button>
    </div>
  </div>
</template>

<!-- {
    config: {
        center: [121.329058, 31.132065],
        zoom: 16,
        show_search: true,
        show_type: true,
    },
    draws: [{
        type: "marker",
        data: {
            position: [121.329058, 31.132065]
        }
    }, {
        type: "marker",
        data: {
            position: [121.328058, 31.132065]
        }
    }, {
        type: "marker",
        data: {
            position: [121.327058, 31.132065]
        }
    }, {
        type: "marker",
        data: {
            position: [121.326058, 31.132065]
        }
    }, {
        type: "polygon",
        data: {
            path: [[
                121.329058 - 0.003,
                31.132065 - 0.002,
            ], [
                121.329058 - 0.002,
                31.132065 + 0.003,
            ], [
                121.329058 + 0.003,
                31.132065 + 0.002,
            ]]
        }
    }]
} -->
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
  emits: ["onStart", "onEnd", "onMarkerStart", "onMarkerEnd"],
  props: {
    mapData: {
      type: Object,
      default: {
        config: {},
        draws: [],
      },
    },
  },
  data() {
    return {
      mapCfg: {
        center: [121.329058, 31.132065],
        zoom: 16,
        show_search: true,
        show_type: true,
      },
      searchWord: "",
      mapType: {
        active: "",
        list: [
          {
            text: "多边形",
            value: "polygon",
          },
          {
            text: "矩形",
            value: "rectangle",
          },
          {
            text: "圆形",
            value: "circle",
          },
          {
            text: "线路",
            value: "polyline",
          },
        ],
      },
      mapTypeLock: false,
      lngLat: [],
      marker: null,
      draw: null,
      drawEditor: false,
    };
  },
  mounted() {
    this.mapCfg = Object.assign(this.mapCfg, this.mapData.config || {});
    this.mapCfg.center = [
      parseFloat(this.mapCfg.center[0]),
      parseFloat(this.mapCfg.center[1]),
    ];
    setTimeout(() => {
      this.initAMap();
    });
  },
  unmounted() {
    this.map?.destroy();
  },
  methods: {
    mapTypeClick(btn) {
      if (this.mapType.active == btn.value || this.mapTypeLock) {
        return;
      }
      this.mapTypeLock = true;
      this.mapType.active = btn.value;
      this.draw && this.draw.close();
      this.draw = null;
      this.marker = null;
      setTimeout(() => {
        this.map.clearMap();
        this.mapAddMarker(this.lngLat);
        this.mapAddDraw(btn.value);
      }, 100);
    },
    initAMap() {
      window._AMapSecurityConfig = {
        securityJsCode: "be523a16326b5165fd8e181dcfeb7cbe",
      };
      AMapLoader.load({
        key: "8ccd91782749f3ea9099fc64be657906",
        version: "2.0",
        plugins: [
          "AMap.Scale",
          "AMap.Bounds",
          "AMap.Marker",
          "AMap.PlaceSearch",
          "AMap.Polygon",
          "AMap.PolygonEditor",
          "AMap.Rectangle",
          "AMap.RectangleEditor",
          "AMap.Circle",
          "AMap.CircleEditor",
          "AMap.Polyline",
          "AMap.PolylineEditor",
          "AMap.Geocoder",
        ],
      })
        .then((AMap) => {
          this.map = new AMap.Map("MAP", {
            viewMode: "2D",
            zoom: this.mapCfg.zoom,
            center: this.mapCfg.center,
          });
          this.lngLat = this.mapCfg.center;
          this.map_search = new AMap.PlaceSearch({
            city: "全国",
          });
          this.mapAddMarker(this.lngLat);
          this.addDraws(this.mapData.draws);
        })
        .catch((e) => {});
    },
    mapSearch(word) {
      this.map.clearMap();
      this.map_search.search(word, (status, result) => {
        let poiList = result.poiList;
        if (result && poiList && poiList.count > 0) {
          this.lngLat = [
            poiList.pois[0].location.lng,
            poiList.pois[0].location.lat,
          ];
          this.map.setCenter(this.lngLat);
          this.mapAddMarker(this.lngLat);
        }
      });
    },
    mapAddMarker(lngLat) {
      this.addDraw("marker", {
        position: lngLat,
        draggable:
          this.mapCfg.show_type || this.mapCfg.show_search ? true : false,
      });
      this.$emit("onMarkerEnd", lngLat);
    },
    mapDrawClose() {
      if (this.draw) {
        this.draw.close();
        this.drawEditor = false;
        this.mapTypeLock = false;
        this.marker.setDraggable(false);
      }
      //回调操作
      let lays = this.map.getAllOverlays(),
        paths = [];
      lays.map((lay) => {
        let path,
          lnglat = [];
        switch (lay.className) {
          case "Overlay.Polygon":
            path = lay.getPath();
            path.map((p) => {
              lnglat.push(`${p.lng},${p.lat}`);
            });
            paths.push({
              id: 2,
              type: "polygon",
              path: lnglat.join(";"),
            });
            break;
          case "Overlay.Rectangle":
            path = lay.ir;
            paths.push({
              id: 3,
              type: "rectangle",
              path: `${path.northEast.lng},${path.northEast.lat};${path.southWest.lng},${path.southWest.lat}`,
            });
            break;
          case "Overlay.Circle":
            path = lay.getCenter();
            paths.push({
              id: 1,
              type: "circle",
              path: `${path.lng},${path.lat};${lay.getRadius()}`,
            });
            break;
          case "Overlay.Polyline":
            path = lay.getPath();
            path.map((p) => {
              lnglat.push(`${p.lng},${p.lat}`);
            });
            paths.push({
              id: 4,
              type: "polyline",
              path: lnglat.join(";"),
            });
            break;
        }
      });
      let marker = this.marker.getPosition(),
        geo = new AMap.Geocoder({
          city: "全国",
          batch: false,
        });
      geo.getAddress(marker, (status, result) => {
        if (status == "complete") {
          paths.push({
            id: 0,
            type: "marker",
            path: `${marker.lng},${marker.lat}`,
            address: result.regeocode.formattedAddress,
          });
          this.$emit("onEnd", paths);
        }
      });
    },
    mapDrawOpen() {
      this.draw.open();
      this.drawEditor = true;
      this.mapTypeLock = true;
      this.marker.setDraggable(true);
      this.$emit("onStart");
    },
    mapAddDraw(type) {
      switch (type) {
        case "polygon":
          this.addDraw("polygon", {
            path: [
              [this.lngLat[0] - 0.003, this.lngLat[1] - 0.002],
              [this.lngLat[0] - 0.002, this.lngLat[1] + 0.003],
              [this.lngLat[0] + 0.003, this.lngLat[1] + 0.002],
            ],
          });
          break;
        case "rectangle":
          this.addDraw("rectangle", {
            bounds: [
              [this.lngLat[0] - 0.003, this.lngLat[1] - 0.002],
              [this.lngLat[0] + 0.003, this.lngLat[1] + 0.002],
            ],
          });
          break;
        case "circle":
          this.addDraw("circle", {
            center: this.lngLat,
            radius: 300,
          });
          break;
        case "polyline":
          this.addDraw("polyline", {
            path: [
              [this.lngLat[0] - 0.003, this.lngLat[1]],
              [this.lngLat[0] + 0.003, this.lngLat[1]],
            ],
          });
          break;
      }
    },
    addDraw(type, data) {
      let draw = null,
        { ...opts } = data || {};
      switch (type) {
        case "marker":
          if (!this.marker) {
            draw = new AMap.Marker(
              Object.assign(
                {
                  zIndex: 999,
                },
                opts
              )
            );
            this.marker = draw;
          } else if (!this.mapCfg.show_type) {
            opts.position = [
              parseFloat(opts.position[0]),
              parseFloat(opts.position[1]),
            ];
            draw = new AMap.Marker(
              Object.assign(
                {
                  zIndex: 999,
                },
                opts
              )
            );
          }
          break;
        case "polygon":
          draw = new AMap.Polygon(
            Object.assign(
              {
                strokeColor: "#FF3333",
                strokeOpacity: 1,
                strokeWeight: 3,
                fillColor: "#FF3333",
                fillOpacity: 0.2,
                strokeStyle: "dashed",
                cursor: "pointer",
                draggable: false,
                strokeDasharray: [5, 5],
              },
              opts
            )
          );
          break;
        case "rectangle":
          if (opts.bounds && opts.bounds.length > 0) {
            opts.bounds.map((data, index) => {
              opts.bounds[index] = [parseFloat(data[0]), parseFloat(data[1])];
            });
            opts.bounds = new AMap.Bounds(opts.bounds[0], opts.bounds[1]);
          }
          draw = new AMap.Rectangle(
            Object.assign(
              {
                map: this.map,
                strokeColor: "#FF3333",
                strokeOpacity: 1,
                strokeWeight: 3,
                fillColor: "#FF3333",
                fillOpacity: 0.2,
                strokeStyle: "dashed",
                cursor: "pointer",
                draggable: false,
                strokeDasharray: [5, 5],
              },
              opts
            )
          );
          break;
        case "circle":
          draw = new AMap.Circle(
            Object.assign(
              {
                strokeColor: "#FF3333",
                strokeOpacity: 1,
                strokeWeight: 3,
                fillColor: "#FF3333",
                fillOpacity: 0.2,
                strokeStyle: "dashed",
                cursor: "pointer",
                draggable: false,
                strokeDasharray: [5, 5],
              },
              opts
            )
          );
          break;
        case "polyline":
          draw = new AMap.Polyline(
            Object.assign(
              {
                strokeColor: "#FF3333",
                strokeOpacity: 1,
                strokeWeight: 6,
                strokeStyle: "dashed",
                cursor: "pointer",
                draggable: false,
                strokeDasharray: [10, 5],
              },
              opts
            )
          );
          break;
      }
      draw && this.map.add(draw);
      if (draw && this.mapCfg.show_type) {
        if (type == "marker") {
          this.marker.on("dragstart", (e) => {
            this.$emit("onMarkerEnd", [e.lnglat.lng, e.lnglat.lat]);
          });
          this.marker.on("dragend", (e) => {
            this.lngLat = [e.lnglat.lng, e.lnglat.lat];
            this.$emit("onMarkerEnd", this.lngLat);
          });
        } else {
          switch (type) {
            case "polygon":
              this.draw = new AMap.PolygonEditor(this.map, draw);
              break;
            case "rectangle":
              this.draw = new AMap.RectangleEditor(this.map, draw);
              break;
            case "circle":
              this.draw = new AMap.CircleEditor(this.map, draw);
              break;
            case "polyline":
              this.draw = new AMap.PolylineEditor(this.map, draw);
              break;
          }
          this.mapDrawOpen();
          this.mapType.active = type;
          this.draw.on(
            "end",
            (e) => {
              e.target.on("dblclick", () => {
                this.mapDrawOpen();
              });
            },
            null,
            true
          );
        }
      }
      return draw;
    },
    addDraws(draws) {
      if (draws && draws.length > 0) {
        for (let i = 0; i < draws.length; i++) {
          const draw = draws[i];
          this.addDraw(draw.type, draw.data);
        }
        if (this.mapCfg.show_type) {
          setTimeout(() => {
            this.mapDrawClose();
          });
        }
      }
    },
  },
};
</script>
<style>
#MAP .amap-marker img {
  width: 19px;
  height: 32px;
}
</style>

<style scoped>
#MAP {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 100%;
  min-height: 300px;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
.map-box {
  position: relative;
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 100%;
  min-height: 300px;
}
.search-box {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 200px;
  z-index: 999;
}
.type-box {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 999;
}
.draw-box {
  position: absolute;
  bottom: 10px;
  right: 10px;
  z-index: 999;
}
</style>
